﻿using MongoDB.Driver;
using MongoDB.Driver.Builders;
using MongoDB.Driver.GridFS;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using YamrSyncDemo.YammerData;
using YamrSyncLib.DBSync;

namespace YamrSyncDemo.DBSync
{
    public class YammerDB
    {
        private string connectionString;
        private string databaseName;
        private MongoClient mongoClient;
        private MongoServer mongoServer;
        public MongoDatabase MongoDatabase { get; private set; }

        public YammerDB(string databaseName, string connectionString = "mongodb://localhost")
        {
            this.connectionString = connectionString;

            // not allowed on Windows for database names: /\. "*<>:|?
            this.databaseName = databaseName;
            var chars = new[] { '/', '\\', '.', ' ', '"', '*', '<', '>', ':', '|', '?' };
            foreach (var c in chars)
            {
                this.databaseName = this.databaseName.Replace(c, '_');
            }
        }

        /// <summary>
        /// Connect to the database.
        /// </summary>
        /// <returns>Returns false if connection cannot be established, true otherwise.</returns>
        public bool Connect()
        {
            // will not throw even if database is not available
            InitDB();
            try
            {
                mongoServer.Connect();
            }
            catch (MongoConnectionException)
            {
                return false;
            }
            return true;
        }

        private void InitDB()
        {
            if (MongoDatabase == null)
            {
                mongoClient = new MongoClient(connectionString);
                mongoServer = mongoClient.GetServer();
                MongoDatabase = mongoServer.GetDatabase(databaseName);
            }
        }

        public void AddOrUpdateMessages(IEnumerable<YammerMessage> messages)
        {
            foreach (YammerMessage ym in messages)
            {
                var collection = MongoDatabase.GetCollection(CollectionNames.Messages);
                var query = Query<YammerMessage>.EQ(e => e.ID, ym.ID);
                var update = Update<YammerMessage>.Replace(ym);
                collection.Update(query, update, UpdateFlags.Upsert);

                if (!string.IsNullOrEmpty(ym.MessageContent.PlainText))
                {
                    var message = "Message:  " + ym.MessageContent.PlainText;
                    Console.WriteLine(message);
                    Debug.WriteLine(message);
                }
                else
                {
                    var message = "Message ID " + ym.ID + "had no message in the body.";
                    Console.WriteLine(message);
                    Debug.WriteLine(message);
                }
            }
        }

        public void AddOrUpdateGroups(ICollection<YammerGroup> groups)
        {
            Debug.WriteLine("Group count: " + groups.Count);
            var groupCollection = MongoDatabase.GetCollection<YammerGroup>("yammer.groups");
            foreach (var group in groups)
            {
                var query = Query<YammerGroup>.EQ(e => e.ID, group.ID);
                var update = Update.Replace<YammerGroup>(group);
                groupCollection.Update(query, update, UpdateFlags.Upsert);

                Debug.WriteLine("Adding/Updating group " + group.FullName);
            }
        }

        public void AddOrUpdateUsers(ICollection<YammerUser> users)
        {
            Debug.WriteLine("User count: " + users.Count);
            var groupCollection = MongoDatabase.GetCollection<YammerGroup>("yammer.users");
            foreach (var user in users)
            {
                var query = Query<YammerUser>.EQ(e => e.UserID, user.UserID);
                var update = Update.Replace<YammerUser>(user);
                groupCollection.Update(query, update, UpdateFlags.Upsert);

                Debug.WriteLine("Adding/Updating user " + user.FullName);
            }
        }

        public void AddOrUpdateAccessibleNetworks(ICollection<YammerNetwork> networks)
        {
            var groupCollection = MongoDatabase.GetCollection<YammerNetwork>("yammer.networks");
            foreach (var network in networks)
            {
                var query = Query<YammerNetwork>.EQ(e => e.NetworkID, network.NetworkID);
                var update = Update.Replace<YammerNetwork>(network);
                groupCollection.Update(query, update, UpdateFlags.Upsert);

                Debug.WriteLine("Adding/Updating network " + network.NetworkName);
            }
        }

        public void AddOrUpdateGroupMembers(YammerGroupMembers members)
        {
            var groupMembersCollection = MongoDatabase.GetCollection<YammerGroupMembers>("yammer.groupmembers");
            var query = Query<YammerGroupMembers>.EQ(e => e.GroupID, members.GroupID);
            var update = Update.Replace<YammerGroupMembers>(members);
            groupMembersCollection.Update(query, update, UpdateFlags.Upsert);
        }

        public MongoCursor<YammerMessage> GetMessagesWithFileAttachments()
        {
            var collection = MongoDatabase.GetCollection<YammerMessage>(CollectionNames.Messages);
            var query = Query.ElemMatch("Attachments", Query.EQ("Type", "file"));
            return collection.Find(query);
        }

        public void SaveStream(Stream stream, string remoteFileName)
        {
            var gridFS = MongoDatabase.GetGridFS(MongoGridFSSettings.Defaults);
            var result = gridFS.Find(remoteFileName);
            if (result.Count() > 0)
            {
                // delete old file
                gridFS.Delete(remoteFileName);
            }
            gridFS.Upload(stream, remoteFileName);

        }
    }
}
